# coding=utf-8

from string import Template
from typing import List
from parse.parse_types import CB, PA
from utils.payload import  VhalType

from utils.util import writeFile

pa_read_property_cpp=Template(
"""
#include <apvp.pb.h>
#include "PlatformProperty.h"

TRANSMIT_READ_PROPERTY(${properyName},${propType}) {
    builder.area(VehicleArea::GLOBAL)
        .initValue([](){
                return ${initValue};
        })
${status_impl}
        .withValueBySignals([]([[maybe_unused]] ${propType} lastValue){
${impl}
        },ecarx::transfer::PASignal::${properyName});
}
"""
)

pa_immutableStatus=Template(
"""
        .immutableStatus(PropertyStatus::Active)
"""
)

pa_Status=Template(
"""
        .withStatusBySignals([](const PropertyStatus lastStatus){
                PropertyStatus currentStatus = PropertyStatus::Active;
                auto paData=SIGNAL.get${PAName}();
                if(paData.availability == toInt(sdb::AvailabilitySts::Active)){
                    currentStatus = PropertyStatus::Active;
                }else if(paData.availability == toInt(sdb::AvailabilitySts::NotActive)){
                    currentStatus = PropertyStatus::NotActive;
                }else if(paData.availability == toInt(sdb::AvailabilitySts::NotAvailable)){
                    currentStatus = PropertyStatus::NotAvailable;
                }else if(paData.availability == toInt(sdb::AvailabilitySts::Error)){
                    currentStatus = PropertyStatus::Error;
                }
                return currentStatus;
        },ecarx::transfer::PASignal::${PAName})
"""
)

pa_data_normal_impl_parse=Template(
"""
            auto paData=SIGNAL.get${PAName}();
            return paData.data;

"""
)

pa_data_string_impl_parse=Template(
"""
            auto paData=SIGNAL.get${PAName}();
            return std::string(reinterpret_cast<char const *>(paData.data));
"""
)

pa_data_array_impl_parse=Template(
"""
            auto paData=SIGNAL.get${PAName}();
            std::vector<${propType}> value(${len});
            memcpy(value.data(), paData.data, ${len});
            return value;

"""
)

templete_pa_struct_parse=Template(
"""
            auto pa=SIGNAL.get${PAName}();
            proto::ipcp::${struct_Type} protoObj;
${members}       
            return protoObj;
"""
)

templete_pa_struct_member_parse=Template(
"""            protoObj.set_${protoMember}(pa.${member});"""
)

cb_write_property_cpp=Template(
"""
#include <apvp.pb.h>
#include "PlatformProperty.h"

TRANSMIT_WRITE_PROPERTY(${properyName},${propType}) {
    builder
        .area(VehicleArea::GLOBAL)
        .immutableStatus(PropertyStatus::Active)
        .onSetProperty([](const ${propType}& value) {
${impl}
        });
}
"""
)

cb_base_type_parse=Template(
"""
            SIGNAL.set${signalName}(value);
"""
)

cb_enum_type_parse=Template(
"""
            SIGNAL.set${signalName}(sdb::${propType}((int32_t)value));
"""
)

cb_array_base_type_parse=Template(
"""
            std::array<${propType},${len}> arr{};
            int32_t realLen = value.size() < ${len} ? value.size() : ${len};
            std::copy_n(value.begin(), realLen, arr.begin());
            SIGNAL.set${signalName}(arr);
"""
)

cb_struct_parse=Template(
"""
            ${struct_Type} structObj;
${members}       
            SIGNAL.set${signalName}(structObj);
"""
)

cb_struct_member_parse=Template(
"""            structObj.${member}=(${convert_type})value.${protoMember}();"""
)


def gen_PACBDirectTransmitPropertyImpl(paSignals:List[PA],cbSignals:List[CB]):
    for pa in paSignals:
        structPayload=pa.getPayload().getStructPayload()
        status_impl=pa_immutableStatus.substitute()
        if pa.available != "NA":
            status_impl=pa_Status.substitute(
                PAName=pa.api
            )
        if pa.mustGenProto():
            members=[]
            for member in structPayload.members:
                members.append(templete_pa_struct_member_parse.substitute(
                        member=member.member_name,
                        protoMember = member.member_name.lower()
                    ))
            
            writeFile("../vhal_platform/directTransmit", "{}.cpp".format(pa.api),
                        lambda file: file.write(pa_read_property_cpp.substitute(
                            properyName=pa.api,
                            propType="proto::ipcp::"+pa.toProtoBufName(),
                            initValue="proto::ipcp::{}{{}}".format(pa.toProtoBufName()),
                            status_impl=status_impl,
                            impl=templete_pa_struct_parse.substitute(
                                    PAName=pa.api,
                                    struct_Type=pa.toProtoBufName(),
                                    members="\n".join(members)
                                )
                        )))
        else:
            if structPayload.type_name == "PAIntFuncType":
                writeFile("../vhal_platform/directTransmit", "{}.cpp".format(pa.api),
                        lambda file: file.write(pa_read_property_cpp.substitute(
                            properyName=pa.api,
                            propType="int32_t",
                            initValue="-1",
                            status_impl=status_impl,
                            impl=pa_data_normal_impl_parse.substitute(
                                    PAName=pa.api,
                                    propType="int32_t",
                                )
                        )))
            elif structPayload.type_name.startswith("PAStringFuncType"):
                writeFile("../vhal_platform/directTransmit", "{}.cpp".format(pa.api),
                        lambda file: file.write(pa_read_property_cpp.substitute(
                            properyName=pa.api,
                            propType="std::string",
                            initValue="\"\"",
                            status_impl=status_impl,
                            impl=pa_data_string_impl_parse.substitute(
                                    PAName=pa.api
                                )
                        )))
            elif structPayload.type_name.startswith("PAIntArrayFuncType"):
                writeFile("../vhal_platform/directTransmit", "{}.cpp".format(pa.api),
                        lambda file: file.write(pa_read_property_cpp.substitute(
                            properyName=pa.api,
                            propType="std::vector<int32_t>",
                            initValue="std::vector<int32_t>{}",
                            status_impl=status_impl,
                            impl=pa_data_array_impl_parse.substitute(
                                    PAName=pa.api,
                                    len=pa.array_len,
                                    propType="int32_t"
                                )
                        )))

    for cb in cbSignals:
        payload =cb.getPayload()
        if payload.isBaseTypePayload():
            basePayload = payload.getBaseTypePayload()
            if basePayload.hasEncodeType():
                writeFile("../vhal_platform/directTransmit", "{}.cpp".format(cb.api),
                        lambda file: file.write(cb_write_property_cpp.substitute(
                            properyName=cb.api,
                            propType=basePayload.getEncodeType().getTypeName(),
                            impl=cb_enum_type_parse.substitute(
                                    signalName=cb.api,
                                    propType=basePayload.getEncodeType().getTypeName(),
                                )
                        )))
            else:
                def toPropType(type):
                    if type.value <=6:
                        return "int32_t"
                    elif type.value <=8:
                        return "int64_t"
                    else:
                        return "float"

                writeFile("../vhal_platform/directTransmit", "{}.cpp".format(cb.api),
                        lambda file: file.write(cb_write_property_cpp.substitute(
                            properyName=cb.api,
                            propType=toPropType(basePayload.type),
                            impl=cb_base_type_parse.substitute(
                                    signalName=cb.api
                                )
                        )))
        elif payload.isArrayPayload():
            arrayPayload = payload.getArrayPayload()
            writeFile("../vhal_platform/directTransmit", "{}.cpp".format(cb.api),
                    lambda file: file.write(cb_write_property_cpp.substitute(
                        properyName=cb.api,
                        propType="std::vector<{}>".format(arrayPayload.array_type.name),
                        impl=cb_array_base_type_parse.substitute(
                                signalName=cb.api,
                                propType = arrayPayload.array_type.name,
                                len=arrayPayload.array_len
                            )
                    )))
        elif payload.isStructPayload():
            structPayload = payload.getStructPayload()
            members=[]
            for member in structPayload.members:
                members.append(cb_struct_member_parse.substitute(
                        member=member.member_name,
                        convert_type=member.member_type.name,
                        protoMember = member.member_name.lower()

                    ))
            writeFile("../vhal_platform/directTransmit", "{}.cpp".format(cb.api),
                lambda file: file.write(cb_write_property_cpp.substitute(
                    properyName=cb.api,
                    propType="proto::ipcp::{}".format(structPayload.type_name),
                    impl=cb_struct_parse.substitute(
                            signalName=cb.api,
                            struct_Type = structPayload.type_name,
                            members="\n".join(members)
                        )
                )))

        
    
           
                

    